home *** CD-ROM | disk | FTP | other *** search
- /*
- ARTemis (Graphic Editor for FM-TOWNS)
- (c) MATSUUCHI Ryosuke 1992
-
- plt16.c
-
- 16色モードにおいてパレットどうしの混色や近似パレット検索を行うときの処理
- */
-
-
- #include <stdio.h>
- #include <malloc.h>
- #include <egb.h>
- #include <memory.h>
-
- #include <math2.h>
- #include <decimal.h>
-
- #include "ge.h"
- #include "plt16.h"
-
-
- #if NO16==0
-
-
- // (local) 指定したパレット番号のパレットを得る
- //-----------------------------------------------------------------------
-
-
- static grb_t _getplt(int plt)
- {
- unsigned char pal_[4+8*16];
- EGB_getPalette(1,(char *)pal_);
- return (int)((pal_[4+8*plt+4+2]>>4)&15)*256 +
- (int)((pal_[4+8*plt+4+1]>>4)&15)* 16 +
- (int)((pal_[4+8*plt+4 ]>>4)&15);
- }
-
-
- // (local) 指定したパレット番号のパレットを設定する
- //-----------------------------------------------------------------------
-
-
- static void _setplt(int plt, grb_t grb)
- {
- char pal_[4+8*16];
- DWORD(pal_ + 0) = 1;
- DWORD(pal_ + 4) = plt;
- BYTE (pal_ + 8) = (grb&15) << 4;
- BYTE (pal_ + 9) = ((grb>>4)&15)<<4;
- BYTE (pal_ +10) = ((grb>>8)&15)<<4;
- BYTE (pal_ +11) = 0;
- EGB_palette(_egbwork,0,pal_);
- }
-
-
- // (local) grb_t カラーどうしの「相違度(difference)」を計算する
- //-----------------------------------------------------------------------
-
-
- /*
- static int _coldiff(grb_t grb1, grb_t grb2)
- {
- static int exp2[] =
- { 0,1,4,9,16,25,36,49,64,81,
- 100,121,144,169,196,225,256 };
- return exp2[_abs((int)((grb1>>8)&15)-(int)((grb2>>8)&15))]
- + exp2[_abs((int)((grb1>>4)&15)-(int)((grb2>>4)&15))]
- + exp2[_abs((int)(grb1&15)-(int)(grb2&15))];
- }
- */
-
-
- static void RGB_YCrCb(int *grb, deci *ycc)
- {
- static const int A[4][4] = {
- {FDeci( 0.29900), FDeci( 0.58700), FDeci( 0.11400)},
- {FDeci( 0.50000), FDeci(-0.41869), FDeci(-0.08131)},
- {FDeci(-0.16874), FDeci(-0.33126), FDeci( 0.50000)}
- };
- ycc[0] = A[0][0] * grb[1] + A[0][1] * grb[0] + A[0][2] * grb[2];
- ycc[1] = A[1][0] * grb[1] + A[1][1] * grb[0] + A[1][2] * grb[2];
- ycc[2] = A[2][0] * grb[1] + A[2][1] * grb[0] + A[2][2] * grb[2];
- return;
- }
-
-
- static int _coldiff(grb_t grb1, grb_t grb2)
- {
- int grb[2][4];
- deci ycc[2][4];
- grb[0][0]=(grb1>>8)&15; grb[0][1]=(grb1>>4)&15; grb[0][2]=(grb1)&15;
- grb[1][0]=(grb2>>8)&15; grb[1][1]=(grb2>>4)&15; grb[1][2]=(grb2)&15;
- RGB_YCrCb(grb[0], ycc[0]);
- RGB_YCrCb(grb[1], ycc[1]);
- int t,d;
- d = 0;
- // 色相(Cr,Cb)の相違
- t = ycc[0][1] - ycc[1][1]; t = MulDeci(MulDeci(t,t),FDeci(0.7));
- d += DeciToInt(t);
- t = ycc[0][2] - ycc[1][2]; t = MulDeci(MulDeci(t,t),FDeci(0.8));
- d += DeciToInt(t);
- // 輝度(Y)の相違
- t = ycc[0][0] - ycc[1][0]; t = MulDeci(t,t);
- d += DeciToInt(t);
- return d;
- }
-
-
- // (local) 近似パレットリストのための型定義・変数定義
- //-----------------------------------------------------------------------
-
-
- typedef struct _nearplt_e { // 近似パレットリストの1要素(NEARPLTの補助)
- struct _nearplt_e *next;
- bool used;
- char plt;
- short int dist;
- } NEARPLTe;
-
-
- typedef struct { // ある grb_t カラーに対する近似パレットリスト
- NEARPLTe *neartop;
- NEARPLTe near[16];
- } NEARPLT;
-
-
- static NEARPLT *nearplt; // 全 grb_t カラーに対する近似パレットリスト
- static grb_t pltgrb[16]; // 各パレットの現在の設定状態
-
-
- // (local) 近似パレットリストへの要素の挿入
- //-----------------------------------------------------------------------
-
-
- static void NEARPLT_ins(grb_t grb, int plt)
- // [grb_tカラー grb に対する近似パレットリストに、plt 番のパレットを挿入する]
- // この関数は、grb_tカラー grb に対する近似パレットリストに plt 番の
- // パレットがまだ登録されていない状態で呼ばなくてはいけない。
- {
- NEARPLT *nplt;
- int dist;
- nplt = nearplt + grb;
- dist = _coldiff(grb, pltgrb[plt]);
- if (nplt->neartop == NULL)
- {
- NEARPLTe *p;
- p = &(nplt->near[0]);
- p->next = NULL;
- p->used = YES;
- p->plt = plt;
- p->dist = dist;
- nplt->neartop = p;
- }
- else
- {
- int i;
- register NEARPLTe *p1,*p2;
- bool done;
- NEARPLTe *p;
- done = NO;
- for (p1=nplt->neartop,p2=NULL; p1!=NULL; p2=p1,p1=p1->next)
- {
- if (dist < p1->dist)
- {
- done = YES;
- for (i=0; i<16; i++)
- if (! nplt->near[i].used) break;
- if (i==16)
- return;
- p = &(nplt->near[i]);
- p->used = YES;
- p->next = p1;
- p->plt = plt;
- p->dist = dist;
- if (p2 == NULL)
- nplt->neartop = p;
- else
- p2->next = p;
- break;
- }
- }
- if (!done)
- {
- for (i=0; i<16; i++)
- if (! nplt->near[i].used) break;
- if (i==16)
- return;
- p = &(nplt->near[i]);
- p->used = YES;
- p->next = NULL;
- p->plt = plt;
- p->dist = dist;
- if (p2 == NULL)
- nplt->neartop = p;
- else
- p2->next = p;
- }
- }
- }
-
-
- // (local) 近似パレットリストの要素の削除
- //-----------------------------------------------------------------------
-
-
- static void NEARPLT_del(int grb, int plt)
- // [grb_tカラー grb に対する近似パレットリストの中から、
- // plt番のパレットの要素を削除する]
- // この関数は、リスト中に見つかった plt 番のパレット要素をすべて
- // 削除する。また、リスト中に plt 番のパレット要素が存在しなくても
- // 問題はない。
- {
- NEARPLT *nplt;
- nplt = nearplt + grb;
- NEARPLTe *p1,*p2;
- for (p1=nplt->neartop,p2=NULL; p1!=NULL; p2=p1,p1=p1->next)
- {
- if (p1->plt == plt)
- {
- if (p2==NULL)
- nplt->neartop = p1->next;
- else
- p2->next = p1->next;
- p1->used = NO;
- }
- }
- }
-
-
- #endif /* if NO16==0 */
-
-
-
- // (global) grb_t カラー 000 に対する近似パレットリストのダンプ出力
- // (デバッグ用関数)
- //-----------------------------------------------------------------------
-
-
- void __dumpNEARPLT0()
- {
- #if NO16==0
- if (mode != MODE16)
- return;
- int tc = 0*256+0*16+0;
- sprintf(debugmsg,"nearplt[%03x] dump:",tc);
- DEBUG_MSG(debugmsg);
- NEARPLTe *p;
- p = (nearplt+tc)->neartop;
- for ( ; p!=NULL; p=p->next)
- {
- sprintf(debugmsg, " %1x[%03x] d%4d", p->plt, plt16_get(p->plt), p->dist);
- DEBUG_MSG(debugmsg);
- }
- #endif
- }
-
-
- // (global) 近似パレットリストおよびこのモジュールの初期化
- //-----------------------------------------------------------------------
-
-
- int plt16_init()
- {
- #if NO16==0
- int i,j;
- if (nearplt == NULL)
- {
- nearplt = calloc(sizeof(NEARPLT), 4096);
- if (nearplt == NULL)
- {
- DEBUG_MSG("近似色リストバッファ 確保失敗");
- return -1;
- }
- else
- DEBUG_MSG("近似色リストバッファ 確保成功");
- }
- else
- memset(nearplt, 0, sizeof(NEARPLT)*4096);
- for (i=0; i<16; i++)
- pltgrb[i] = _getplt(i);
- for (i=0; i<4096; i++)
- for (j=0; j<16; j++)
- NEARPLT_ins(i,j);
- __dumpNEARPLT0();
- #endif
- return 0;
- }
-
-
- // (global) 指定したパレット番号に対するパレットの設定
- //-----------------------------------------------------------------------
-
-
- void plt16_set(int plt, grb_t grb)
- {
- #if NO16==0
- int i;
- for (i=0; i<4096; i++)
- NEARPLT_del(i,plt);
- _setplt(plt, grb);
- pltgrb[plt] = grb;
- for (i=0; i<4096; i++)
- NEARPLT_ins(i,plt);
- #endif
- }
-
-
- // (global) 指定したパレット番号に対するパレット内容を得る
- //-----------------------------------------------------------------------
-
-
- grb_t plt16_get(int plt)
- {
- #if NO16==0
- return pltgrb[plt];
- #else
- return 0;
- #endif
- }
-
-
- // (global) 指定した grb_t カラーの近似パレットを得る
- //-----------------------------------------------------------------------
-
-
- int plt16_getnear(grb_t grb, int source_plt, int object_plt)
- // 指定されたRGBカラーに最も近いパレットを返す
- {
- #if NO16==0
- NEARPLT *nplt;
- nplt = nearplt + grb;
- NEARPLTe *p;
- p = nplt->neartop;
- if (p->plt != source_plt)
- return p->plt;
- else // 「一番近い色」がもとの色と同じ色の場合
- {
- int distmax = (nearplt+pltgrb[p->plt])->near[object_plt].dist;
- // distmax = _min(distmax, _coldiff(pltgrb[source_plt], pltgrb[object_plt]));
- for (p=p->next; p!=NULL; p=p->next)
- {
- if ((nearplt+pltgrb[p->plt])->near[object_plt].dist < distmax)
- return p->plt;
- }
- return object_plt;
- }
- #else
- return 0;
- #endif
- }
-
-
- // (global) 指定した2つの grb_t カラーを混ぜ合わせる
- //-----------------------------------------------------------------------
-
-
- grb_t plt16_gray(grb_t grb1, grb_t grb2, int gray)
- // gray : 0..256(grb2の「強さ」)
- {
- #if NO16==0
- if (gray == 0)
- return grb1;
- else if (gray == 256)
- return grb2;
- else
- {
- gray = _min(256,_max(gray,0));
- int gg,r1,r2,g1,g2,b1,b2,r,g,b;
- gg = 256-gray;
- g1 = (grb1>>8)&15;
- r1 = (grb1>>4)&15;
- b1 = grb1 & 15;
- g2 = (grb2>>8)&15;
- r2 = (grb2>>4)&15;
- b2 = grb2 & 15;
- g = (gg*g1 + gray*g2 + 128) / 256;
- r = (gg*r1 + gray*r2 + 128) / 256;
- b = (gg*b1 + gray*b2 + 128) / 256;
- return (g<<8)|(r<<4)|b;
- }
- #else
- return 0;
- #endif
- }
-
-
- /* end of plt16.c */
-